<template>
  <div class="line-chart-container">
    <div class="chart-header">
      <div class="zoom-controls">
        <!-- 时间选择器组 -->
        <!-- <div class="control-group time-range-group">
          <label class="control-label">时间范围:</label>
          <DatePicker
            type="datetimerange"
            v-model="dateTimeRange"
            @on-ok="handleTimeRangeChange"
            style="width: 280px"
            placeholder="选择时间范围"
            class="time-picker"
          ></DatePicker>
        </div> -->

        <!-- 缩放信息组 -->
        <div class="control-group zoom-info-group">
          <span class="zoom-percent"
            >缩放: {{ Math.round(zoomLevel * 100) }}%</span
          >
          <div class="zoom-mode-buttons">
            <button
              @click="setZoomMode('global')"
              :class="['mode-btn', { active: zoomMode === 'global' }]"
            >
              全局视图
            </button>
            <button
              @click="setZoomMode('detail')"
              :class="['mode-btn', { active: zoomMode === 'detail' }]"
            >
              细节视图
            </button>
          </div>
        </div>

        <!-- 操作按钮组 -->
        <div class="control-group action-buttons-group">
          <button class="action-btn reset-btn" @click="resetZoom">
            重置缩放
          </button>
          <button
            v-if="printEnabled"
            class="action-btn print-btn"
            @click="printChart"
          >
            打印
          </button>
          <button
            v-if="exportImageEnabled"
            class="action-btn export-btn"
            @click="exportAsImage"
          >
            导出图片
          </button>
        </div>
      </div>
    </div>

    <!-- 图纸信息表格 - 使用配置动态生成 -->
    <div class="drawing-info-section">
      <div class="drawing-info-grid">
        <div
          v-for="field in drawingInfoFields"
          :key="field.key"
          class="info-field"
        >
          <label class="field-label">{{ field.label }}</label>
          <input
            v-model="drawingInfoFields[field.key]"
            class="field-input"
            :disabled="!field.editable || !drawingInfoEditable"
            :placeholder="field.defaultValue || ''"
          />
        </div>
      </div>
    </div>

    <div
      ref="chartContainer"
      class="chart-wrapper"
      @wheel="handleWheel"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      @mouseleave="handleMouseUp"
    >
      <!-- 网格背景 -->
      <svg
        class="grid-svg"
        :width="containerWidth"
        :height="containerHeight"
        :viewBox="`0 0 ${containerWidth} ${containerHeight}`"
      >
        <!-- 右上角横向图例 -->
        <g class="horizontal-top-right-legend" v-if="dataTypes.length > 0">
          <!-- 半透明背景 -->
          <rect
            :x="horizontalLegendPosition.x - 8"
            :y="horizontalLegendPosition.y - 8"
            :width="horizontalLegendPosition.totalWidth + 16"
            height="30"
            fill="rgba(255, 255, 255, 0.92)"
            stroke="rgba(224, 224, 224, 0.9)"
            stroke-width="1"
            rx="4"
            class="legend-background"
          />

          <!-- 横向排列的图例项 -->
          <g
            v-for="(item, index) in legendItems"
            :key="item.type"
            class="legend-item"
          >
            <!-- 计算每个图例项的起始位置 -->
            <line
              :x1="
                horizontalLegendPosition.x +
                  index * (horizontalLegendPosition.itemWidth + 15)
              "
              :y1="horizontalLegendPosition.y + 7"
              :x2="
                horizontalLegendPosition.x +
                  index * (horizontalLegendPosition.itemWidth + 15) +
                  18
              "
              :y2="horizontalLegendPosition.y + 7"
              :stroke="item.color"
              stroke-width="2"
              stroke-linecap="round"
              class="legend-line"
            />

            <!-- 文本标签 -->
            <text
              :x="
                horizontalLegendPosition.x +
                  index * (horizontalLegendPosition.itemWidth + 15) +
                  22
              "
              :y="horizontalLegendPosition.y + 10"
              font-size="11"
              fill="#333"
              text-anchor="start"
              class="legend-text"
            >
              {{ item.label }}
            </text>
          </g>
        </g>

        <!-- 网格线 -->
        <g class="grid-lines">
          <!-- 精细网格线 -->
          <g v-for="(tick, index) in fineGridLines" :key="`fine-${index}`">
            <!-- 垂直精细网格线 -->
            <line
              v-if="tick.type === 'vertical' && fineGridLinesEnabled"
              :x1="tick.x1"
              :y1="tick.y1"
              :x2="tick.x2"
              :y2="tick.y2"
              :stroke="fineGridLineStroke"
              :stroke-width="fineGridLineStrokeWidth"
            />
            <!-- 水平精细网格线 -->
            <line
              v-if="tick.type === 'horizontal' && fineGridLinesEnabled"
              :x1="tick.x1"
              :y1="tick.y1"
              :x2="tick.x2"
              :y2="tick.y2"
              :stroke="fineGridLineStroke"
              :stroke-width="fineGridLineStrokeWidth"
            />
          </g>

          <!-- 主网格线 -->
          <g v-for="(tick, index) in mainGridLines" :key="`main-${index}`">
            <!-- 垂直主网格线 -->
            <line
              v-if="tick.type === 'vertical'"
              :x1="tick.x1"
              :y1="tick.y1"
              :x2="tick.x2"
              :y2="tick.y2"
              :stroke="mainGridLineStroke"
              :stroke-width="mainGridLineStrokeWidth"
            />
            <!-- 水平主网格线 -->
            <line
              v-if="tick.type === 'horizontal'"
              :x1="tick.x1"
              :y1="tick.y1"
              :x2="tick.x2"
              :y2="tick.y2"
              :stroke="mainGridLineStroke"
              :stroke-width="mainGridLineStrokeWidth"
            />
          </g>
        </g>

        <!-- 坐标轴 -->
        <g class="axes">
          <!-- X轴 -->
          <line
            :x1="paddingLeft"
            :y1="containerHeight - paddingBottom"
            :x2="containerWidth - paddingRight"
            :y2="containerHeight - paddingBottom"
            :stroke="axisStroke"
            :stroke-width="axisStrokeWidth"
          />
          <!-- Y轴 -->
          <line
            :x1="paddingLeft"
            :y1="paddingTop"
            :x2="paddingLeft"
            :y2="containerHeight - paddingBottom"
            :stroke="axisStroke"
            :stroke-width="axisStrokeWidth"
          />
        </g>

        <!-- 标尺刻度 -->
        <g class="ruler-marks">
          <!-- X轴刻度 -->
          <g v-for="(tick, index) in xAxisTicks" :key="`x-${index}`">
            <line
              :x1="tick.x"
              :y1="containerHeight - paddingBottom"
              :x2="tick.x"
              :y2="containerHeight - paddingBottom + 5"
              :stroke="xAxisTickColor"
              stroke-width="1"
            />
            <text
              :x="tick.x"
              :y="containerHeight - paddingBottom + 15"
              text-anchor="middle"
              :font-size="xAxisTickFontSize"
              :fill="xAxisTickColor"
            >
              {{ tick.label }}
            </text>
          </g>

          <!-- Y轴刻度 -->
          <g v-for="(tick, index) in yAxisTicks" :key="`y-${index}`">
            <line
              :x1="paddingLeft"
              :y1="tick.y"
              :x2="paddingLeft - 5"
              :y2="tick.y"
              :stroke="yAxisTickColor"
              stroke-width="1"
            />
            <text
              :x="paddingLeft - 15"
              :y="tick.y + 4"
              text-anchor="end"
              :font-size="yAxisTickFontSize"
              :fill="yAxisTickColor"
            >
              {{ tick.label }}
            </text>
          </g>
        </g>

        <!-- 折线图 -->
        <g class="line-chart">
          <path
            v-for="(path, type) in linePaths"
            :key="type"
            :d="path"
            fill="none"
            :stroke="getLineColor(type)"
            :stroke-width="lineStrokeWidth"
          />

          <!-- 数据点 -->
          <circle
            v-for="(point, index) in chartPoints"
            :key="`point-${index}`"
            :cx="point.x"
            :cy="point.y"
            :r="getPointRadius(index)"
            :fill="getPointColor(index)"
            stroke="#fff"
            stroke-width="2"
            @mouseenter="showTooltip($event, index)"
            @mouseleave="hideTooltip"
            style="cursor: pointer"
          />

          <!-- 异常值标签 -->
          <text
            v-for="(item, index) in outlierLabels"
            :key="`label-${index}`"
            :x="item.point.x"
            :y="getLabelY(item.point.y, item.value)"
            text-anchor="middle"
            :font-size="outlierLabelsFontSize"
            :fill="outlierLabelsColor"
            :font-weight="outlierLabelsFontWeight"
          >
            {{ item.value.toFixed(1) }}{{ yAxisTickFormat }}
          </text>
        </g>
      </svg>

      <!-- 悬停提示框 -->
      <div
        v-if="tooltip.visible"
        class="tooltip"
        :style="{
          left: tooltip.x + 'px',
          top: tooltip.y + 'px',
          backgroundColor: tooltipBackgroundColor,
          color: tooltipColor,
          fontSize: tooltipFontSize,
          padding: tooltipPadding,
          borderRadius: tooltipBorderRadius
        }"
      >
        {{ tooltip.value }}{{ yAxisTickFormat }}
      </div>
    </div>

    <o-card-box :isExpand="false" :width="400">
      <vxe-grid
        ref="xGrid"
        v-bind="gridOptions"
        @page-change="pageChange"
      ></vxe-grid>
    </o-card-box>
  </div>
</template>

<script lang="ts">
import { Component, Ref, Vue, Prop, Watch } from 'vue-property-decorator';
import {
  Tsrv,
  getGridOptions,
  getConfig,
  I_cmd,
  T_cmd,
  N_cChartView,
  ifs,
  T_srv
} from './config';

@Component
export default class LineChartWithRuler extends Vue {
  @Ref('chartContainer') chartContainer!: HTMLElement;

  @Prop() config: N_cChartView.config;

  private apiData: N_cChartView.Data[] = [];

  /* 父组件compBoxInfo */
  @T_srv.prop({
    required: false,
    type: Object,
    default: null
  })
  compBoxInfo: ifs.I_compBoxInfo;

  /* 组件名 */
  private name: string = 'LineChartWithRuler';

  private funName: string = 'LineChartWithRuler';

  private G_compName: string = this.name;

  /* 组件箱信息对象 */
  private GT_compBoxInfo: ifs.I_compBoxInfo;

  /* 组件箱对象 */
  private GT_compBox: ifs.I_compBox;

  /* 组件箱识别ID */
  private G_compID: string;

  // 容器尺寸
  containerWidth = 1200;

  containerHeight = 800;

  padding = 60;

  paddingLeft = 80;

  paddingRight = 20;

  paddingTop = 20;

  paddingBottom = 50;

  // 网格和缩放
  gridSize = 20;

  // 基础网格大小
  zoomLevel = 1;

  minZoom = 0.1;

  maxZoom = 5;

  // 拖拽状态
  isDragging = false;

  lastMouseX = 0;

  lastMouseY = 0;

  translateX = 0;

  translateY = 0;

  // 时间范围配置
  timeRange = 'day'; // 'day', 'week'

  // 日期范围
  private startDate;

  private endDate;

  // 温度数据 - 初始化为空数组，在mounted中初始化
  sampleData: N_cChartView.Point[] = [];

  useSecondsDisplay = false;

  // 缩放模式
  zoomMode: 'global' | 'detail' = 'global';

  public gridOptions = getGridOptions();

  private reqParam = null;

  // 配置相关属性
  private chartConfig: any = null;

  private drawingInfoFields: any[] = [];

  /* 指挥部 */
  private GT_command: I_cmd = new T_cmd();

  // 悬停提示框
  tooltip = {
    visible: false,
    x: 0,
    y: 0,
    value: 0
  };

  // 计算属性
  get startDateString(): string {
    return this.startDate.toISOString().split('T')[0];
  }

  set startDateString(value: string) {
    this.startDate = new Date(value);
  }

  get endDateString(): string {
    return this.endDate.toISOString().split('T')[0];
  }

  set endDateString(value: string) {
    this.endDate = new Date(value);
  }

  // 根据type字段分组数据
  get groupedData(): Record<string, N_cChartView.Data[]> {
    const groups: Record<string, N_cChartView.Data[]> = {};
    this.apiData.forEach(item => {
      if (!groups[item.type]) {
        groups[item.type] = [];
      }
      groups[item.type].push(item);
    });
    return groups;
  }

  // 获取所有数据类型
  get dataTypes(): string[] {
    return Object.keys(this.groupedData);
  }

  // 线条颜色配置 - 动态生成
  private lineColors: Record<string, string> = {};

  // 获取线条颜色 - 优先使用配置中的颜色
  getLineColor(type: string): string {
    const lineTypeConfig = this.chartConfig?.chartConfig?.lineTypes?.[type];
    return (
      lineTypeConfig?.stroke ||
      this.lineColors[type] ||
      this.lineColors.default ||
      '#ff4d4f'
    );
  }

  // 获取线条显示标签
  getLineLabel(type: string): string {
    const lineTypeConfig = this.chartConfig?.chartConfig?.lineTypes?.[type];
    return lineTypeConfig?.label || type;
  }

  // private dateTimeRange = [null, null];

  get chartTitle(): string {
    if (this.timeRange === 'custom') {
      const startStr = this.startDate.toLocaleDateString();
      const endStr = this.endDate.toLocaleDateString();
      return `(${startStr} - ${endStr})`;
    }
    if (this.timeRange === 'week') {
      return '(最近7天)';
    }
    return '(最近1天)';
  }

  // 精细网格大小 - 根据缩放级别调整
  get fineGridSize(): number {
    if (this.zoomLevel >= 3) {
      return 5; // 高倍缩放时，精细网格为5px
    }
    if (this.zoomLevel >= 2) {
      return 10; // 中等缩放时，精细网格为10px
    }
    if (this.zoomLevel >= 1) {
      return 20; // 正常缩放时，精细网格为20px
    }
    return 40; // 缩小视图时，精细网格为40px
  }

  // 精细网格细分数量 - 用于调试显示
  get fineGridSubdivisionCount(): number {
    if (this.zoomLevel >= 4) return 10; // 超高倍缩放：10等分
    if (this.zoomLevel >= 3) return 8; // 高倍缩放：8等分
    if (this.zoomLevel >= 2) return 5; // 中高倍缩放：5等分
    if (this.zoomLevel >= 1.5) return 4; // 中倍缩放：4等分
    if (this.zoomLevel >= 1) return 3; // 正常缩放：3等分
    return 2; // 缩小：2等分
  }

  // 异常值标签 - 只在全局视图显示
  get outlierLabels(): Array<{ point: N_cChartView.Point; value: number }> {
    if (this.zoomMode !== 'global') return [];

    const labels: Array<{ point: N_cChartView.Point; value: number }> = [];
    this.chartPoints.forEach((point, index) => {
      if (this.isOutlier(index)) {
        labels.push({
          point,
          value: this.getOriginalValue(index)
        });
      }
    });
    return labels;
  }

  // 配置相关的计算属性
  get lineStroke(): string {
    return (
      (this.chartConfig &&
        this.chartConfig.chartConfig &&
        this.chartConfig.chartConfig.line &&
        this.chartConfig.chartConfig.line.stroke) ||
      '#ff4d4f'
    );
  }

  get lineStrokeWidth(): number {
    return (
      (this.chartConfig &&
        this.chartConfig.chartConfig &&
        this.chartConfig.chartConfig.line &&
        this.chartConfig.chartConfig.line.strokeWidth) ||
      2
    );
  }

  get pointRadius(): number {
    const pointsConfig = this.chartConfig?.chartConfig?.points;
    return pointsConfig?.radius || 4;
  }

  get outlierPointRadius(): number {
    const pointsConfig = this.chartConfig?.chartConfig?.points;
    return pointsConfig?.outlierRadius || 6;
  }

  get normalPointColor(): string {
    const pointsConfig = this.chartConfig?.chartConfig?.points;
    return pointsConfig?.normalColor || '#ff4d4f';
  }

  get outlierPointColor(): string {
    const pointsConfig = this.chartConfig?.chartConfig?.points;
    return pointsConfig?.outlierColor || '#ff1744';
  }

  // 网格配置相关的计算属性
  get mainGridLineStroke(): string {
    const gridConfig = this.chartConfig?.chartConfig?.grid;
    return gridConfig?.mainLines?.stroke || '#e0e0e0';
  }

  get mainGridLineStrokeWidth(): number {
    const gridConfig = this.chartConfig?.chartConfig?.grid;
    return gridConfig?.mainLines?.strokeWidth || 1;
  }

  get fineGridLineStroke(): string {
    const gridConfig = this.chartConfig?.chartConfig?.grid;
    return gridConfig?.fineLines?.stroke || '#e0e0e0';
  }

  get fineGridLineStrokeWidth(): number {
    const gridConfig = this.chartConfig?.chartConfig?.grid;
    return gridConfig?.fineLines?.strokeWidth || 1;
  }

  get fineGridLinesEnabled(): boolean {
    const gridConfig = this.chartConfig?.chartConfig?.grid;
    return gridConfig?.fineLines?.enabled !== false; // 默认启用
  }

  // 坐标轴配置相关的计算属性
  get axisStroke(): string {
    const axesConfig = this.chartConfig?.chartConfig?.axes;
    return axesConfig?.stroke || '#333';
  }

  get axisStrokeWidth(): number {
    const axesConfig = this.chartConfig?.chartConfig?.axes;
    return axesConfig?.strokeWidth || 2;
  }

  // X轴配置相关的计算属性
  get xAxisTickFontSize(): number {
    const xAxisConfig = this.chartConfig?.chartConfig?.xAxis;
    return xAxisConfig?.ticks?.fontSize || 12;
  }

  get xAxisTickColor(): string {
    const xAxisConfig = this.chartConfig?.chartConfig?.xAxis;
    return xAxisConfig?.ticks?.color || '#333';
  }

  // Y轴配置相关的计算属性
  get yAxisTickFontSize(): number {
    const yAxisConfig = this.chartConfig?.chartConfig?.yAxis;
    return yAxisConfig?.ticks?.fontSize || 12;
  }

  get yAxisTickColor(): string {
    const yAxisConfig = this.chartConfig?.chartConfig?.yAxis;
    return yAxisConfig?.ticks?.color || '#333';
  }

  get yAxisTickFormat(): string {
    const yAxisConfig = this.chartConfig?.chartConfig?.yAxis;
    return yAxisConfig?.ticks?.format || '°C';
  }

  // 悬停提示框配置相关的计算属性
  get tooltipBackgroundColor(): string {
    const tooltipConfig = this.chartConfig?.chartConfig?.tooltip;
    return tooltipConfig?.backgroundColor || 'rgba(0, 0, 0, 0.8)';
  }

  get tooltipColor(): string {
    const tooltipConfig = this.chartConfig?.chartConfig?.tooltip;
    return tooltipConfig?.color || 'white';
  }

  get tooltipFontSize(): string {
    const tooltipConfig = this.chartConfig?.chartConfig?.tooltip;
    return tooltipConfig?.fontSize || '12px';
  }

  get tooltipPadding(): string {
    const tooltipConfig = this.chartConfig?.chartConfig?.tooltip;
    return tooltipConfig?.padding || '4px 8px';
  }

  get tooltipBorderRadius(): string {
    const tooltipConfig = this.chartConfig?.chartConfig?.tooltip;
    return tooltipConfig?.borderRadius || '4px';
  }

  // 异常值标签配置相关的计算属性
  get outlierLabelsEnabled(): boolean {
    const outlierConfig = this.chartConfig?.chartConfig?.outlierLabels;
    return outlierConfig?.enabled !== false; // 默认启用
  }

  get outlierLabelsFontSize(): number {
    const outlierConfig = this.chartConfig?.chartConfig?.outlierLabels;
    return outlierConfig?.fontSize || 10;
  }

  get outlierLabelsColor(): string {
    const outlierConfig = this.chartConfig?.chartConfig?.outlierLabels;
    return outlierConfig?.color || '#ff4d4f';
  }

  get outlierLabelsFontWeight(): string {
    const outlierConfig = this.chartConfig?.chartConfig?.outlierLabels;
    return outlierConfig?.fontWeight || 'bold';
  }

  // 缩放配置相关的计算属性
  get minZoomLevel(): number {
    const zoomConfig = this.chartConfig?.chartConfig?.zoom;
    return zoomConfig?.minZoom || 0.1;
  }

  get maxZoomLevel(): number {
    const zoomConfig = this.chartConfig?.chartConfig?.zoom;
    return zoomConfig?.maxZoom || 5;
  }

  get defaultZoomLevel(): number {
    const zoomConfig = this.chartConfig?.chartConfig?.zoom;
    return zoomConfig?.defaultZoom || 1;
  }

  // 功能开关配置相关的计算属性
  get zoomEnabled(): boolean {
    const featuresConfig = this.chartConfig?.features;
    return featuresConfig?.zoom !== false; // 默认启用
  }

  get dragEnabled(): boolean {
    const featuresConfig = this.chartConfig?.features;
    return featuresConfig?.drag !== false; // 默认启用
  }

  get printEnabled(): boolean {
    const featuresConfig = this.chartConfig?.features;
    return featuresConfig?.print !== false; // 默认启用
  }

  get exportImageEnabled(): boolean {
    const featuresConfig = this.chartConfig?.features;
    return featuresConfig?.exportImage !== false; // 默认启用
  }

  // get timeRangeSelectorEnabled(): boolean {
  //   const featuresConfig = this.chartConfig?.features;
  //   return featuresConfig?.timeRangeSelector !== false; // 默认启用
  // }

  get drawingInfoEditable(): boolean {
    const featuresConfig = this.chartConfig?.features;
    return featuresConfig?.drawingInfoEditable !== false; // 默认启用
  }

  // 主网格线 - 完全覆盖XY轴围成的区域
  get mainGridLines(): Array<{
    type: 'vertical' | 'horizontal';
    x1: number;
    y1: number;
    x2: number;
    y2: number;
  }> {
    const lines: Array<{
      type: 'vertical' | 'horizontal';
      x1: number;
      y1: number;
      x2: number;
      y2: number;
    }> = [];

    // 定义网格区域边界
    const gridLeft = this.paddingLeft;
    const gridRight = this.containerWidth - this.paddingRight;
    const gridTop = this.paddingTop;
    const gridBottom = this.containerHeight - this.paddingBottom;

    // 垂直主网格线 - 与X轴刻度对齐
    const xTicks = this.xAxisTicks;
    xTicks.forEach(tick => {
      if (tick.x !== undefined) {
        lines.push({
          type: 'vertical',
          x1: tick.x,
          y1: gridTop,
          x2: tick.x,
          y2: gridBottom
        });
      }
    });

    // 水平主网格线 - 与Y轴刻度对齐
    const yTicks = this.yAxisTicks;
    yTicks.forEach(tick => {
      if (tick.y !== undefined) {
        lines.push({
          type: 'horizontal',
          x1: gridLeft,
          y1: tick.y,
          x2: gridRight,
          y2: tick.y
        });
      }
    });

    return lines;
  }

  // 精细网格线 - 在刻度之间添加更细的网格，完全覆盖XY轴区域
  get fineGridLines(): Array<{
    type: 'vertical' | 'horizontal';
    x1: number;
    y1: number;
    x2: number;
    y2: number;
  }> {
    const lines: Array<{
      type: 'vertical' | 'horizontal';
      x1: number;
      y1: number;
      x2: number;
      y2: number;
    }> = [];

    // 定义网格区域边界
    const gridLeft = this.paddingLeft;
    const gridRight = this.containerWidth - this.paddingRight;
    const gridTop = this.paddingTop;
    const gridBottom = this.containerHeight - this.paddingBottom;

    // 根据缩放级别确定细分数量
    const getSubdivisionCount = (): number => {
      if (this.zoomLevel >= 4) return 10; // 超高倍缩放：10等分
      if (this.zoomLevel >= 3) return 8; // 高倍缩放：8等分
      if (this.zoomLevel >= 2) return 5; // 中高倍缩放：5等分
      if (this.zoomLevel >= 1.5) return 4; // 中倍缩放：4等分
      if (this.zoomLevel >= 1) return 3; // 正常缩放：3等分
      return 2; // 缩小：2等分
    };

    const subdivisionCount = getSubdivisionCount();

    // 垂直精细网格线
    const xTicks = this.xAxisTicks;
    for (let i = 0; i < xTicks.length - 1; i++) {
      const startX = xTicks[i].x || 0;
      const endX = xTicks[i + 1].x || 0;
      const segmentWidth = (endX - startX) / subdivisionCount;

      for (let j = 1; j < subdivisionCount; j++) {
        const x = startX + j * segmentWidth;
        lines.push({
          type: 'vertical',
          x1: x,
          y1: gridTop,
          x2: x,
          y2: gridBottom
        });
      }
    }

    // 水平精细网格线
    const yTicks = this.yAxisTicks;
    for (let i = 0; i < yTicks.length - 1; i++) {
      const startY = yTicks[i].y || 0;
      const endY = yTicks[i + 1].y || 0;
      const segmentHeight = (endY - startY) / subdivisionCount;

      for (let j = 1; j < subdivisionCount; j++) {
        const y = startY + j * segmentHeight;
        lines.push({
          type: 'horizontal',
          x1: gridLeft,
          y1: y,
          x2: gridRight,
          y2: y
        });
      }
    }

    return lines;
  }

  get chartPoints(): N_cChartView.Point[] {
    const chartWidth =
      this.containerWidth - this.paddingLeft - this.paddingRight;
    const chartHeight =
      this.containerHeight - this.paddingTop - this.paddingBottom;

    // 根据时间范围确定X轴范围
    const { maxX, minX } = this.GT_command.getTimeRange();

    // 动态计算Y轴范围
    const { maxY, minY } = this.getTemperatureRange();

    return this.sampleData.map(point => ({
      x: this.paddingLeft + ((point.x - minX) / (maxX - minX)) * chartWidth,
      y:
        this.paddingTop +
        chartHeight -
        ((point.y - minY) / (maxY - minY)) * chartHeight
    }));
  }

  get linePaths(): Record<string, string> {
    const paths: Record<string, string> = {};
    const chartWidth =
      this.containerWidth - this.paddingLeft - this.paddingRight;
    const chartHeight =
      this.containerHeight - this.paddingTop - this.paddingBottom;
    const { maxX, minX } = this.GT_command.getTimeRange();
    const { maxY, minY } = this.getTemperatureRange();

    this.dataTypes.forEach(type => {
      const points = this.groupedData[type]
        .map(item => {
          const date = new Date(item.name);
          const minutes = this.calculateMinutesFromStartDate(date);
          return {
            x:
              this.paddingLeft +
              ((minutes - minX) / (maxX - minX)) * chartWidth,
            y:
              this.paddingTop +
              chartHeight -
              ((item.value - minY) / (maxY - minY)) * chartHeight
          };
        })
        .sort((a, b) => a.x - b.x);

      if (points.length > 0) {
        let path = `M ${points[0].x} ${points[0].y}`;
        for (let i = 1; i < points.length; i++) {
          path += ` L ${points[i].x} ${points[i].y}`;
        }
        paths[type] = path;
      }
    });

    return paths;
  }

  // 保持向后兼容的单个折线路径
  get linePath(): string {
    if (this.dataTypes.length === 0) return '';

    // 如果有多个类型，返回第一个类型的路径
    const firstType = this.dataTypes[0];
    return this.linePaths[firstType] || '';
  }

  get xAxisTicks(): N_cChartView.Tick[] {
    const ticks: N_cChartView.Tick[] = [];
    const chartWidth =
      this.containerWidth - this.paddingLeft - this.paddingRight;
    const { minX, maxX } = this.GT_command.getTimeRange();
    const timeRange = maxX - minX;

    // 根据缩放级别动态调整刻度数量
    let tickCount: number;
    if (this.zoomLevel >= 4) {
      tickCount = Math.floor(chartWidth / 10); // 超高倍缩放：密集刻度
    } else if (this.zoomLevel >= 3) {
      tickCount = Math.floor(chartWidth / 15); // 高倍缩放：较密集刻度
    } else if (this.zoomLevel >= 2) {
      tickCount = Math.floor(chartWidth / 20); // 中高倍缩放：中等刻度
    } else if (this.zoomLevel >= 1) {
      tickCount = Math.floor(chartWidth / 30); // 正常缩放：标准刻度
    } else if (this.zoomLevel >= 0.5) {
      tickCount = Math.floor(chartWidth / 40); // 缩小：稀疏刻度
    } else {
      tickCount = Math.floor(chartWidth / 60); // 最小：最稀疏刻度
    }

    // 确保刻度数量在合理范围内
    tickCount = Math.max(3, Math.min(tickCount, 20));

    // 计算时间步长
    const timeStep = timeRange / tickCount;

    for (let i = 0; i <= tickCount; i++) {
      const x = this.paddingLeft + (i / tickCount) * chartWidth;
      const timeValue = minX + i * timeStep;

      // 格式化时间标签
      const label = this.GT_command.formatTimeLabel(timeValue);

      ticks.push({
        x,
        label
      });
    }

    // 确保第一个刻度在Y轴位置，最后一个刻度在X轴右端点
    if (ticks.length > 0) {
      ticks[0].x = this.paddingLeft; // 第一个刻度在Y轴
      ticks[ticks.length - 1].x = this.containerWidth - this.paddingRight; // 最后一个刻度在X轴右端点
    }
    return ticks;
  }

  get yAxisTicks(): N_cChartView.Tick[] {
    const ticks: N_cChartView.Tick[] = [];
    const chartHeight =
      this.containerHeight - this.paddingTop - this.paddingBottom;
    const { minY, maxY } = this.getTemperatureRange();
    const tempRange = maxY - minY;

    // 根据缩放级别动态调整刻度数量
    let tickCount: number;
    if (this.zoomLevel >= 4) {
      tickCount = Math.floor(chartHeight / 15); // 超高倍缩放：密集刻度
    } else if (this.zoomLevel >= 3) {
      tickCount = Math.floor(chartHeight / 20); // 高倍缩放：较密集刻度
    } else if (this.zoomLevel >= 2) {
      tickCount = Math.floor(chartHeight / 25); // 中高倍缩放：中等刻度
    } else if (this.zoomLevel >= 1) {
      tickCount = Math.floor(chartHeight / 30); // 正常缩放：标准刻度
    } else if (this.zoomLevel >= 0.5) {
      tickCount = Math.floor(chartHeight / 40); // 缩小：稀疏刻度
    } else {
      tickCount = Math.floor(chartHeight / 50); // 最小：最稀疏刻度
    }

    // 确保刻度数量在合理范围内
    tickCount = Math.max(3, Math.min(tickCount, 15));

    // 生成合适的刻度值
    const tickValues = this.GT_command.generateNiceTicks(minY, maxY, tickCount);

    tickValues.forEach(tempValue => {
      const y =
        this.paddingTop + ((maxY - tempValue) / tempRange) * chartHeight;
      ticks.push({
        y,
        label: `${tempValue.toFixed(3)}${this.yAxisTickFormat}`
      });
    });

    // 确保第一个刻度在X轴位置，最后一个刻度在Y轴顶部
    if (ticks.length > 0) {
      ticks[0].y = this.containerHeight - this.paddingBottom; // 第一个刻度在X轴
      ticks[ticks.length - 1].y = this.paddingTop; // 最后一个刻度在Y轴顶部
    }

    return ticks;
  }

  get legendItems(): Array<{
    type: string;
    label: string;
    color: string;
  }> {
    return this.dataTypes.map(type => {
      const lineTypeConfig = this.chartConfig?.chartConfig?.lineTypes?.[type];
      return {
        type,
        label: lineTypeConfig?.label || type,
        color: lineTypeConfig?.stroke || this.getLineColor(type)
      };
    });
  }

  // 右上角横向图例位置计算
  get horizontalLegendPosition(): {
    x: number;
    y: number;
    itemWidth: number;
    totalWidth: number;
  } {
    const itemCount = this.legendItems.length;
    const itemWidth = 90; // 每个图例项宽度
    const itemSpacing = 15; // 项间距

    const totalWidth = itemCount * itemWidth + (itemCount - 1) * itemSpacing;

    return {
      x: this.containerWidth - this.paddingRight - totalWidth - 10, // 距离右边10px
      y: this.paddingTop - 25, // 在paddingTop上方25px
      itemWidth,
      totalWidth
    };
  }

  // 获取温度范围 - 更新为考虑所有类型数据
  getTemperatureRange(): { minY: number; maxY: number } {
    if (this.apiData.length === 0) {
      return { minY: 0, maxY: 10 };
    }

    // 获取所有数据点的值，包括所有类型
    const allValues = this.apiData.map(item => item.value);
    // const minTemp = Math.min(...allValues);
    // const maxTemp = Math.max(...allValues);
    // const tempRange = maxTemp - minTemp;

    // 检测异常值
    const { normalRange, hasOutliers } = this.detectOutliers(allValues);

    // 根据缩放级别智能调整显示范围
    return this.calculateSmartRange(allValues, normalRange, hasOutliers);
  }

  // 智能计算显示范围
  calculateSmartRange(
    temperatures: number[],
    normalRange: { min: number; max: number },
    hasOutliers: boolean
  ): { minY: number; maxY: number } {
    const minTemp = Math.min(...temperatures);
    const maxTemp = Math.max(...temperatures);
    const totalRange = maxTemp - minTemp;
    const normalTempRange = normalRange.max - normalRange.min;

    // 根据缩放模式和缩放级别决定显示策略
    if (this.zoomMode === 'detail') {
      // 细节模式：优先显示正常范围，突出小数级变化
      if (normalTempRange < 1) {
        const margin = Math.max(normalTempRange * 0.2, 0.05);
        return {
          minY: normalRange.min - margin,
          maxY: normalRange.max + margin
        };
      }
      const margin = normalTempRange * 0.1;
      return {
        minY: normalRange.min - margin,
        maxY: normalRange.max + margin
      };
    }

    // 全局模式：根据缩放级别调整
    if (this.zoomLevel >= 3) {
      // 高倍缩放：显示正常范围，突出细节
      if (normalTempRange < 1) {
        const margin = Math.max(normalTempRange * 0.2, 0.05);
        return {
          minY: normalRange.min - margin,
          maxY: normalRange.max + margin
        };
      }
      const margin = normalTempRange * 0.1;
      return {
        minY: normalRange.min - margin,
        maxY: normalRange.max + margin
      };
    }
    if (this.zoomLevel >= 2) {
      // 中等缩放：平衡显示
      if (hasOutliers && normalTempRange < totalRange * 0.3) {
        const margin = Math.max(normalTempRange * 0.15, 0.1);
        return {
          minY: normalRange.min - margin,
          maxY: normalRange.max + margin
        };
      }
      const margin = totalRange * 0.05;
      return {
        minY: minTemp - margin,
        maxY: maxTemp + margin
      };
    }
    if (this.zoomLevel >= 1) {
      // 正常缩放：显示全部范围
      const margin = totalRange * 0.05;
      return {
        minY: minTemp - margin,
        maxY: maxTemp + margin
      };
    }
    // 缩小视图：显示全部范围，包括异常值
    const margin = totalRange * 0.1;
    return {
      minY: minTemp - margin,
      maxY: maxTemp + margin
    };
  }

  // 检测异常值
  detectOutliers(
    temperatures: number[]
  ): { normalRange: { min: number; max: number }; hasOutliers: boolean } {
    if (temperatures.length < 3) {
      return {
        normalRange: {
          min: Math.min(...temperatures),
          max: Math.max(...temperatures)
        },
        hasOutliers: false
      };
    }

    // 计算中位数和四分位数
    const sorted = [...temperatures].sort((a, b) => a - b);
    const q1 = sorted[Math.floor(sorted.length * 0.25)];
    const q3 = sorted[Math.floor(sorted.length * 0.75)];
    const iqr = q3 - q1;

    // 定义异常值边界
    const lowerBound = q1 - 1.5 * iqr;
    const upperBound = q3 + 1.5 * iqr;

    // 检查是否有异常值
    const outliers = temperatures.filter(
      temp => temp < lowerBound || temp > upperBound
    );
    const normalTemps = temperatures.filter(
      temp => temp >= lowerBound && temp <= upperBound
    );

    if (outliers.length > 0 && outliers.length < temperatures.length * 0.1) {
      // 如果异常值少于10%，认为是异常值
      return {
        normalRange: {
          min: Math.min(...normalTemps),
          max: Math.max(...normalTemps)
        },
        hasOutliers: true
      };
    }

    return {
      normalRange: {
        min: Math.min(...temperatures),
        max: Math.max(...temperatures)
      },
      hasOutliers: false
    };
  }

  // 计算双Y轴范围
  calculateDualAxisRange(
    normalRange: { min: number; max: number },
    allTemperatures: number[]
  ): { minY: number; maxY: number } {
    const normalTempRange = normalRange.max - normalRange.min;

    // 如果正常范围很小（小于1度），使用正常范围
    if (normalTempRange < 1) {
      const margin = Math.max(normalTempRange * 0.2, 0.05);
      return {
        minY: normalRange.min - margin,
        maxY: normalRange.max + margin
      };
    }

    // 否则使用全部数据范围，但添加适当边距
    const minTemp = Math.min(...allTemperatures);
    const maxTemp = Math.max(...allTemperatures);
    const totalRange = maxTemp - minTemp;
    const margin = totalRange * 0.05; // 5%边距

    return {
      minY: minTemp - margin,
      maxY: maxTemp + margin
    };
  }

  // 根据缩放级别计算刻度步长
  getTickStep(): number {
    // 更精细的缩放级别控制，支持更大的缩放范围
    if (this.zoomLevel >= 4) return 0.5; // 超高倍缩放：30秒间隔
    if (this.zoomLevel >= 3) return 1; // 高倍缩放：1分钟间隔
    if (this.zoomLevel >= 2) return 2; // 中高倍缩放：2分钟间隔
    if (this.zoomLevel >= 1.5) return 5; // 中倍缩放：5分钟间隔
    if (this.zoomLevel >= 1) return 10; // 正常缩放：10分钟间隔
    if (this.zoomLevel >= 0.5) return 20; // 缩小：20分钟间隔
    if (this.zoomLevel >= 0.2) return 60; // 更小：1小时间隔
    return 120; // 最小：2小时间隔
  }

  // 鼠标滚轮事件处理
  handleWheel(event: WheelEvent): void {
    if (!this.zoomEnabled) return;

    event.preventDefault();

    const delta = event.deltaY > 0 ? 0.9 : 1.1;
    const newZoom = this.zoomLevel * delta;

    if (newZoom >= this.minZoom && newZoom <= this.maxZoom) {
      this.zoomLevel = newZoom;
      // 移除自动模式切换，让缩放和视图模式独立工作
    }
  }

  // 鼠标按下事件
  handleMouseDown(event: MouseEvent): void {
    if (!this.dragEnabled) return;

    this.isDragging = true;
    this.lastMouseX = event.clientX;
    this.lastMouseY = event.clientY;
  }

  // 鼠标移动事件
  handleMouseMove(event: MouseEvent): void {
    if (!this.isDragging) return;

    const deltaX = event.clientX - this.lastMouseX;
    const deltaY = event.clientY - this.lastMouseY;

    this.translateX += deltaX;
    this.translateY += deltaY;

    this.lastMouseX = event.clientX;
    this.lastMouseY = event.clientY;
  }

  // 鼠标释放事件
  handleMouseUp(): void {
    this.isDragging = false;
  }

  // 重置缩放
  resetZoom(): void {
    this.zoomLevel = 1;
    this.translateX = 0;
    this.translateY = 0;
  }

  // 设置缩放模式
  setZoomMode(mode: 'global' | 'detail'): void {
    this.zoomMode = mode;
    // 模式切换时重新计算图表
    this.$forceUpdate();
  }

  // 获取数据点的半径
  getPointRadius(index: number): number {
    if (this.isOutlier(index)) {
      return this.outlierPointRadius; // 异常值用更大的点
    }
    return this.pointRadius; // 正常值用标准大小的点
  }

  // 获取数据点的颜色
  getPointColor(index: number): string {
    if (this.isOutlier(index)) {
      return this.outlierPointColor; // 异常值用更鲜艳的红色
    }
    return this.normalPointColor; // 正常值用标准红色
  }

  // 判断是否为异常值
  isOutlier(index: number): boolean {
    if (index < 0 || index >= this.sampleData.length) return false;

    const temperatures = this.sampleData.map(p => p.y);
    const { normalRange } = this.detectOutliers(temperatures);

    const value = this.sampleData[index].y;
    return value < normalRange.min || value > normalRange.max;
  }

  // 获取原始数值
  getOriginalValue(index: number): number {
    if (index < 0 || index >= this.sampleData.length) return 0;
    return this.sampleData[index].y;
  }

  // 获取标签Y坐标 - 根据数值大小决定显示在点的上方还是下方
  getLabelY(pointY: number, value: number): number {
    const { minY, maxY } = this.getTemperatureRange();
    const tempRange = maxY - minY;
    const chartHeight = this.containerHeight - 2 * this.padding;

    // 计算当前值在温度范围中的相对位置
    const relativePosition = (value - minY) / tempRange;

    // 如果值在温度范围的上半部分，标签显示在点的上方
    // 如果值在温度范围的下半部分，标签显示在点的下方
    if (relativePosition > 0.5) {
      return pointY - 10; // 显示在点的上方
    }
    return pointY + 15; // 显示在点的下方
  }

  // 计算打印时的标签Y位置
  getPrintLabelY(
    pointY: number,
    value: number,
    printHeight: number,
    printPadding: number
  ): number {
    const { minY, maxY } = this.getTemperatureRange();
    const tempRange = maxY - minY;
    const relativePosition = (value - minY) / tempRange;

    // 如果值在温度范围的上半部分，标签显示在点上方
    // 如果值在温度范围的下半部分，标签显示在点下方
    if (relativePosition > 0.5) {
      return pointY - 10; // 上方
    }
    return pointY + 15; // 下方
  }

  // 显示悬停提示框
  showTooltip(event: MouseEvent, index: number): void {
    const rect = (event.target as Element)
      .closest('.chart-wrapper')
      ?.getBoundingClientRect();
    if (!rect) return;

    this.tooltip = {
      visible: true,
      x: event.clientX - rect.left,
      y: event.clientY - rect.top - 30,
      value: this.getOriginalValue(index)
    };
  }

  // 隐藏悬停提示框
  hideTooltip(): void {
    this.tooltip.visible = false;
  }

  // 打印图表
  printChart(): void {
    // 创建打印窗口
    const printWindow = window.open('', '_blank');
    if (!printWindow) {
      console.error('无法打开打印窗口，请检查浏览器设置');
      return;
    }

    // 获取两个主要部分的HTML
    const drawingInfoHTML = this.generatePrintDrawingInfoTable();
    const chartWrapperHTML = this.getChartWrapperHTML();

    // 使用配置中的标题
    const chartTitle = this.chartConfig?.modal?.title || '图表打印';

    // 生成打印内容
    const printContent = `
      <!DOCTYPE html>
      <html>
      <head>
        <title>${chartTitle}</title>
        <style>
          @page {
            size: A4 landscape;
            margin: 0.5cm;
          }
          
          body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 10px;
            background: white;
            width: 100%;
            box-sizing: border-box;
          }
          
          .print-container {
            display: flex;
            flex-direction: column;
            gap: 20px;
          }
          
          .drawing-info-print {
            margin-bottom: 15px;
          }
          
          .drawing-info-print .drawing-info-section {
            margin: 0;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            overflow: hidden;
          }
          
          .drawing-info-print .drawing-info-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 10px;
            padding: 10px;
          }
          
          .drawing-info-print .info-field {
            display: flex;
            flex-direction: column;
            gap: 4px;
          }
          
          .drawing-info-print .field-label {
            font-size: 12px;
            color: #6c757d;
            font-weight: 500;
          }
          
          .drawing-info-print span {
            padding: 5px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 12px;
            background: white;
          }
          
          .chart-wrapper-print {
            width: 100%;
            min-height: 500px;
          }
          
          .chart-wrapper-print svg {
            width: 100% !important;
            height: auto !important;
            display: block !important;
          }
          
          /* 确保打印样式正确 */
          @media print {
            body {
              -webkit-print-color-adjust: exact;
              print-color-adjust: exact;
              width: 100%;
            }
            
            .print-container {
              page-break-inside: avoid;
            }
            
            .drawing-info-print,
            .chart-wrapper-print {
              page-break-inside: avoid;
            }
          }
        </style>
      </head>
      <body>
        <div class="print-container">
          <table class="drawing-info-print">${drawingInfoHTML}</table>
          <div class="chart-wrapper-print">${chartWrapperHTML}</div>
        </div>
      </body>
      </html>
    `;

    // 写入内容并打印
    printWindow.document.write(printContent);
    printWindow.document.close();

    // 等待内容加载完成后打印
    printWindow.onload = () => {
      setTimeout(() => {
        printWindow.print();
        printWindow.close();
      }, 500);
    };
  }

  // 计算最佳打印尺寸
  calculatePrintDimensions(): {
    width: number;
    height: number;
    padding: number;
  } {
    // A4横向页面尺寸 (约29.7cm x 21cm)
    // 考虑边距后可用空间约27.7cm x 19cm
    // 转换为像素 (96 DPI): 约1044px x 720px
    // 为了充分利用页面宽度，使用更大的尺寸
    return {
      width: 800, // 大幅减少宽度
      height: 400, // 大幅减少高度
      padding: 30 // 大幅减少内边距
    };
  }

  // 生成打印用的SVG
  generatePrintSVG(dimensions: {
    width: number;
    height: number;
    padding: number;
  }): string {
    const { minX, maxX } = this.GT_command.getTimeRange();
    const { minY, maxY } = this.getTemperatureRange();
    const timeRange = maxX - minX;
    const tempRange = maxY - minY;

    // 使用计算的最佳尺寸
    const printWidth = dimensions.width;
    const printHeight = dimensions.height;
    const printPadding = dimensions.padding;
    const chartWidth = printWidth - 2 * printPadding;
    const chartHeight = printHeight - 2 * printPadding;

    // 计算数据点位置
    const chartPoints = this.sampleData.map(point => ({
      x: printPadding + ((point.x - minX) / timeRange) * chartWidth,
      y:
        printPadding +
        chartHeight -
        ((point.y - minY) / tempRange) * chartHeight
    }));

    // 生成折线路径
    let linePath = '';
    if (chartPoints.length > 0) {
      linePath = `M ${chartPoints[0].x} ${chartPoints[0].y}`;
      for (let i = 1; i < chartPoints.length; i++) {
        linePath += ` L ${chartPoints[i].x} ${chartPoints[i].y}`;
      }
    }

    // 生成X轴刻度
    const xTicks = this.generatePrintTicks(
      minX,
      maxX,
      chartWidth,
      printPadding,
      'x'
    );
    // 生成Y轴刻度
    const yTicks = this.generatePrintTicks(
      minY,
      maxY,
      chartHeight,
      printPadding,
      'y'
    );

    return `
      <svg width="${printWidth}" height="${printHeight}" viewBox="0 0 ${printWidth} ${printHeight}" style="display: block;">
        <!-- 网格背景 -->
        <defs>
          <pattern id="printGrid" width="20" height="20" patternUnits="userSpaceOnUse">
            <path d="M 20 0 L 0 0 0 20" fill="none" stroke="#e0e0e0" stroke-width="1"/>
          </pattern>
        </defs>
        <rect x="${printPadding}" y="${printPadding}" width="${chartWidth}" height="${chartHeight}" fill="url(#printGrid)"/>
        
        <!-- 坐标轴 -->
        <line x1="${printPadding}" y1="${printHeight -
      printPadding}" x2="${printWidth - printPadding}" y2="${printHeight -
      printPadding}" stroke="#333" stroke-width="2"/>
        <line x1="${printPadding}" y1="${printPadding}" x2="${printPadding}" y2="${printHeight -
      printPadding}" stroke="#333" stroke-width="2"/>
        
        <!-- X轴刻度 -->
        ${xTicks
          .map(
            tick => `
          <line x1="${tick.x}" y1="${printHeight - printPadding}" x2="${
              tick.x
            }" y2="${printHeight -
              printPadding +
              5}" stroke="#333" stroke-width="1"/>
          <text x="${tick.x}" y="${printHeight -
              printPadding +
              15}" text-anchor="middle" font-size="10" fill="#333">${
              tick.label
            }</text>
        `
          )
          .join('')}
        
        <!-- Y轴刻度 -->
        ${yTicks
          .map(
            tick => `
          <line x1="${printPadding}" y1="${tick.y}" x2="${printPadding -
              5}" y2="${tick.y}" stroke="#333" stroke-width="1"/>
          <text x="${printPadding - 10}" y="${tick.y +
              4}" text-anchor="end" font-size="10" fill="#333">${
              tick.label
            }</text>
        `
          )
          .join('')}
        
        <!-- 折线图 -->
        <path d="${linePath}" fill="none" stroke="#ff4d4f" stroke-width="2"/>
        
        <!-- 数据点 -->
        ${chartPoints
          .map(
            (point, index) => `
          <circle cx="${point.x}" cy="${point.y}" r="3" fill="#ff4d4f" stroke="#fff" stroke-width="1"/>
        `
          )
          .join('')}
        
        <!-- 异常值标签 - 只在全局视图显示 -->
        ${
          this.zoomMode === 'global'
            ? chartPoints
                .map((point, index) => {
                  if (this.isOutlier(index)) {
                    const value = this.getOriginalValue(index);
                    const labelY = this.getPrintLabelY(
                      point.y,
                      value,
                      printHeight,
                      printPadding
                    );
                    return `
                <text x="${
                  point.x
                }" y="${labelY}" text-anchor="middle" font-size="10" fill="#ff4d4f" font-weight="bold">
                  ${value.toFixed(1)}°C
                </text>
              `;
                  }
                  return '';
                })
                .filter(label => label !== '')
                .join('')
            : ''
        }
      </svg>
    `;
  }

  // 生成打印用的刻度
  generatePrintTicks(
    min: number,
    max: number,
    size: number,
    padding: number,
    axis: 'x' | 'y'
  ): Array<{ x?: number; y?: number; label: string }> {
    const range = max - min;
    const tickCount = Math.floor(size / 80); // 每80像素一个刻度
    const step = range / tickCount;

    const ticks = [];
    for (let i = 0; i <= tickCount; i++) {
      const value = min + i * step;
      const position = padding + (i / tickCount) * size;

      if (axis === 'x') {
        ticks.push({
          x: position,
          label: this.GT_command.formatTimeLabel(value)
        });
      } else {
        ticks.push({
          y: position,
          label: `${value.toFixed(3)}${this.yAxisTickFormat}`
        });
      }
    }

    return ticks;
  }

  // 导出为图片
  exportAsImage(): void {
    const svgElement = this.$el.querySelector('.grid-svg') as SVGElement;
    if (!svgElement) {
      console.error('无法找到图表元素');
      return;
    }

    // 创建canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    if (!ctx) {
      console.error('无法创建画布');
      return;
    }

    // 设置canvas尺寸
    canvas.width = this.containerWidth;
    canvas.height = this.containerHeight;

    // 设置白色背景
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 将SVG转换为图片
    const svgData = new XMLSerializer().serializeToString(svgElement);
    const svgBlob = new Blob([svgData], {
      type: 'image/svg+xml;charset=utf-8'
    });
    const svgUrl = URL.createObjectURL(svgBlob);

    const img = new Image();
    img.onload = () => {
      // 绘制图片到canvas
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

      // 转换为图片并下载
      canvas.toBlob(blob => {
        if (blob) {
          const url = URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = url;
          link.download = `${this.chartConfig.modal.title} ${
            this.timeRange
          }_${new Date().toISOString().slice(0, 10)}.png`;
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          URL.revokeObjectURL(url);
        }
      }, 'image/png');

      URL.revokeObjectURL(svgUrl);
    };

    img.src = svgUrl;
  }

  // 处理API数据
  processApiData(): N_cChartView.Point[] {
    if (this.apiData && this.apiData.length > 0) {
      return this.convertApiDataToChartData(this.apiData);
    }
    return [];
    // return this.GT_command.generateTemperatureData(); // 备用数据
  }

  // 解析固定格式的时间字符串
  parseFixedTimeFormat(timeString: string): Date {
    // 格式: "2025-09-15 23:37:38"
    const [datePart, timePart] = timeString.split(' ');
    const [year, month, day] = datePart.split('-').map(Number);
    const [hours, minutes, seconds] = timePart.split(':').map(Number);

    return new Date(year, month - 1, day, hours, minutes, seconds);
  }

  // 计算从起始日期开始的时间（分钟或秒，根据显示模式决定）
  calculateMinutesFromStartDate(date: Date): number {
    if (!this.startDate || !date) {
      return 0; // 返回默认值而不是NaN
    }

    const timeDiff = date.getTime() - this.startDate.getTime();

    // 如果使用秒级显示，返回秒数
    if (this.useSecondsDisplay) {
      const seconds = Math.floor(timeDiff / 1000); // 转换为秒
      return Math.max(0, seconds);
    }

    // 否则返回分钟数
    const minutes = Math.floor(timeDiff / (1000 * 60)); // 转换为分钟
    return Math.max(0, minutes);
  }

  // 转换API数据为图表数据格式
  convertApiDataToChartData(
    apiData: Array<{ name: string; value: number; type: string }>
  ): N_cChartView.Point[] {
    if (apiData.length === 0) return [];

    // 首先检测时间间隔
    this.detectTimeIntervalFromRawData(apiData);

    // 转换并排序
    const convertedData = apiData
      .map(item => {
        try {
          const date = new Date(item.name);
          const minutes = this.calculateMinutesFromStartDate(date);

          // 确保分钟数是有效数字
          if (isNaN(minutes)) {
            console.warn('无效的时间计算:', item.name, minutes);
            return null;
          }

          return {
            x: minutes,
            y: item.value
          };
        } catch (error) {
          console.warn('时间格式解析错误:', item.name, error);
          return null;
        }
      })
      .filter(item => item !== null && !isNaN(item.x)) // 过滤掉解析失败和无效的数据
      .sort((a, b) => a.x - b.x); // 按时间正序排序

    return convertedData;
  }

  // 从原始API数据检测时间间隔
  private detectTimeIntervalFromRawData(
    apiData: Array<{ name: string; value: number; type: string }>
  ): void {
    if (apiData.length < 2) return;

    // 计算平均时间间隔（秒）
    let totalInterval = 0;
    for (let i = 1; i < apiData.length; i++) {
      try {
        const prevDate = new Date(apiData[i - 1].name);
        const currentDate = new Date(apiData[i].name);
        const timeDiff = currentDate.getTime() - prevDate.getTime();
        totalInterval += timeDiff / 1000; // 转换为秒
      } catch (error) {
        console.warn('时间格式解析错误:', error);
      }
    }
    const averageInterval = totalInterval / (apiData.length - 1);

    // 如果平均间隔小于60秒，使用秒级显示
    if (averageInterval < 60) {
      this.useSecondsDisplay = true;
      // 添加中文反馈消息
      this.$Message.info('检测到高频数据，已自动切换到秒级显示模式');
    } else {
      this.useSecondsDisplay = false;
    }
  }

  // 检测时间间隔并设置显示模式
  private detectTimeIntervalAndSetMode(data: N_cChartView.Point[]): void {
    if (data.length < 2) return;

    // 计算平均时间间隔（秒）
    let totalInterval = 0;
    for (let i = 1; i < data.length; i++) {
      totalInterval += data[i].x - data[i - 1].x; // 直接使用计算出的时间单位
    }
    const averageInterval = totalInterval / (data.length - 1);

    // 如果平均间隔小于60秒，使用秒级显示
    if (averageInterval < 60) {
      this.useSecondsDisplay = true;
      // 添加中文反馈消息
      this.$Message.info('检测到高频数据，已自动切换到秒级显示模式');
    } else {
      this.useSecondsDisplay = false;
    }
  }

  // 数据转换方法 - 根据配置转换API数据
  private transformApiData(
    apiData: any[]
  ): Array<{ name: string; value: number; type: string }> {
    const transformConfig = this.chartConfig?.dataSource?.dataProcessing
      ?.transform;
    if (!transformConfig || !transformConfig.fieldMapping) {
      return apiData; // 如果没有配置转换，直接返回原数据
    }

    return apiData.map(item => {
      const transformedItem: any = {};
      transformConfig.fieldMapping.forEach((mapping: any) => {
        const sourceValue = item[mapping.source];
        // 这里可以添加更多的转换逻辑，如格式化、类型转换等
        transformedItem[mapping.target] = sourceValue;
      });
      return transformedItem;
    });
  }

  created() {
    // 如果父组件没有传参，那就产生一个
    this.GT_compBoxInfo = Tsrv.getCompInfo(this.compBoxInfo);
    this.G_compID = this.GT_compBoxInfo.compID;
    this.GT_compBox = this.GT_compBoxInfo.TcompBox;
    this.GT_command.init(this, this.GT_compBoxInfo);
    // 初始化配置
    this.initializeConfig();
    // 初始化逻辑已移到mounted中，确保日期正确初始化
    this.init();
  }

  // 组件挂载后初始化
  mounted(): void {
    /* 向父组件发送实例 */
    this.GT_compBox.addCompMergeName(this.G_compID, this.G_compName, this);
    this.$emit('compBoxInfo', this.GT_compBoxInfo);
    if (this.apiData && this.apiData.length > 0) {
      // 初始化默认日期
      this.updateStartEndDate();

      // 处理数据（确保日期初始化完成）
      this.sampleData = this.processApiData();
      this.loadTableData();
    }

    // 使用nextTick确保DOM完全渲染后再更新尺寸
    this.$nextTick(() => {
      this.updateContainerSize();
    });
    window.addEventListener('resize', this.updateContainerSize);
  }

  destroyed() {
    /* 注册组件销毁 */
    this.GT_compBox.removeCompMergeName(this.G_compID, this.G_compName);

    /* 如果父组件传入的compBoxInfo则删除本文件产生的引用,反之是本组件产生的ID统一删除 */
    if (Tsrv.utils.isEmpty(this.compBoxInfo)) {
      this.GT_compBox.removeCompsWithCompID(this.G_compID);
    } else {
      this.GT_compBox.removeCompsMergeName(this.G_compID, [
        `'${this.G_compName}'`
      ]);
    }
  }

  private init() {
    this.reqParam = Tsrv.utils.clone(
      this.config?.config?.dataSource?.params,
      true
    );
    this.loadChartData();
  }

  private loadChartData() {
    this.getChartData().then(([resp, err]) => {
      if (err) {
        this.$msg(err);
        // this.setEchartsData([], []);
        // this.setEchartsData();
      }
      this.apiData = [];

      if (this.chartConfig?.dataSource?.dataProcessing?.needUnzip) {
        const chartData = wUnZipStr(resp?.data).getReturnData('data');
        Object.keys(chartData).forEach(key =>
          chartData[key].d.forEach(item => {
            this.apiData.push({
              ...item,
              label: key
            });
          })
        );
      } else {
        this.apiData = resp?.data;
      }
      if (!Tsrv.noValue(this.apiData)) {
        // 先进行数据转换
        this.apiData = this.transformApiData(this.apiData);
        this.loadData();
      } else {
        this.sampleData = [];
        this.loadTableData();
      }
    });
  }

  private getChartData(): Promise<any> {
    const reqConfig = this.config.config;

    let param = Tsrv.utils.clone(this.reqParam, true);
    if (Tsrv.noValue(reqConfig?.dataSource?.url))
      return Promise.resolve([null, 'no url']);
    if (
      Tsrv.noValue(this.reqParam) ||
      Object.keys(this.reqParam).length === 0
    ) {
      param = {};
    }
    if (reqConfig?.dataSource?.method === 'post') {
      return Tsrv.standardPostReq<any, any>(param, reqConfig.dataSource.url);
    }
    let url: string = Tsrv.utils.clone(reqConfig.dataSource.url);
    if (!Tsrv.noValue(param) && Object.keys(param).length > 0) {
      url = url.concat('?');
      const ps = Object.keys(param);
      for (let i = 0; i < ps.length; i++) {
        if (i === ps.length - 1) {
          url = url.concat(`${ps[i]}=${param[ps[i]]}`);
        } else {
          url = url.concat(`${ps[i]}=${param[ps[i]]}&`);
        }
      }
    }
    return Tsrv.standardGetReq<any, any>({}, url);
  }

  private loadData() {
    if (this.apiData && this.apiData.length > 0) {
      this.updateStartEndDate();
      this.sampleData = this.convertApiDataToChartData(this.apiData);
      this.loadTableData();
    } else {
      // this.sampleData = this.GT_command.generateTemperatureData();
    }
  }

  // 初始化配置
  private initializeConfig(): void {
    // this.chartConfig = getConfig().chartView;
    this.chartConfig = Tsrv.utils.clone(this.config.config, true);
    this.applyDrawingInfoConfig();
    this.applyChartStyleConfig();
  }

  // 应用图纸信息配置
  private applyDrawingInfoConfig(): void {
    const drawingInfoConfig = this.chartConfig?.drawingInfo;
    if (drawingInfoConfig && drawingInfoConfig.fields) {
      this.drawingInfoFields = drawingInfoConfig.fields;
    }
  }

  // 应用图表样式配置
  private applyChartStyleConfig(): void {
    const chartConfig = this.chartConfig?.chartConfig;
    if (chartConfig) {
      // 应用容器配置
      this.containerWidth = chartConfig.container?.width || 1200;
      this.containerHeight = chartConfig.container?.height || 800;

      // 应用内边距配置
      if (chartConfig.container?.padding) {
        this.paddingLeft = chartConfig.container.padding.left || 80;
        this.paddingRight = chartConfig.container.padding.right || 20;
        this.paddingTop = chartConfig.container.padding.top || 20;
        this.paddingBottom = chartConfig.container.padding.bottom || 50;
      }
    }
  }

  // 组件销毁前清理
  beforeDestroy(): void {
    window.removeEventListener('resize', this.updateContainerSize);
  }

  // 更新开始结束时间
  private updateStartEndDate(): void {
    this.endDate = new Date(this.apiData[this.apiData.length - 1].name);
    this.startDate = new Date(this.apiData[0].name);

    // const startTimeField = this.getMappedTimeFieldName('startTime');
    // const endTimeField = this.getMappedTimeFieldName('endTime');
    // this.dateTimeRange = [
    //   new Date(this.reqParam[startTimeField]),
    //   new Date(this.reqParam[endTimeField])
    // ];
  }

  // 更新容器尺寸
  updateContainerSize(): void {
    if (this.chartContainer) {
      const rect = this.chartContainer.getBoundingClientRect();
      // 使用容器的实际尺寸，但确保最小尺寸
      this.containerWidth = Math.max(1200, rect.width);
      // this.containerHeight = Math.max(800, rect.height);
    }
  }

  /**
   * pageChange 翻页
   */
  private pageChange(e: any) {
    if (
      this.gridOptions.pagerConfig.currentPage !== e.currentPage ||
      this.gridOptions.pagerConfig.pageSize !== e.pageSize
    ) {
      this.gridOptions.pagerConfig.currentPage = e.currentPage;
      this.gridOptions.pagerConfig.pageSize = e.pageSize;
      // this.setPage();
      // this.loadChartData();
      this.loadTableData();
    }
  }

  private loadTableData() {
    const grid: any = this.$refs.xGrid;
    grid.reloadData(this.apiData);
  }

  // private handleTimeRangeChange() {
  //   const startTimeField = this.getMappedTimeFieldName('startTime');
  //   const endTimeField = this.getMappedTimeFieldName('endTime');

  //   this.reqParam[startTimeField] = this.dateTimeRange[0];
  //   this.reqParam[endTimeField] = this.dateTimeRange[1];

  //   this.loadChartData();
  // }

  // 获取映射后的时间字段名
  // private getMappedTimeFieldName(internalFieldName: string): string {
  //   const mapping = this.chartConfig?.dataSource?.timeFieldMapping;
  //   return mapping?.[internalFieldName] || internalFieldName; // 如果没有映射，使用原字段名
  // }

  // 获取图纸信息HTML
  private getDrawingInfoHTML(): string {
    const element = this.$el.querySelector('.drawing-info-section');
    if (element) {
      const clone = element.cloneNode(true) as HTMLElement;
      // 处理输入框，转换为只读文本
      const inputs = clone.querySelectorAll('input');
      inputs.forEach(input => {
        const span = document.createElement('span');
        span.textContent = input.value || input.placeholder || '';
        span.style.fontSize = '12px';
        input.parentNode?.replaceChild(span, input);
      });
      return clone.outerHTML;
    }
    return '';
  }

  // 获取图表包装器HTML
  private getChartWrapperHTML(): string {
    const element = this.$el.querySelector('.chart-wrapper');
    if (element) {
      const clone = element.cloneNode(true) as HTMLElement;
      // 移除交互元素（如按钮、工具提示等）
      const interactiveElements = clone.querySelectorAll('button, .tooltip');
      interactiveElements.forEach(el => el.remove());
      return clone.outerHTML;
    }
    return '';
  }

  // 生成打印用的图纸信息表格
  private generatePrintDrawingInfoTable(): string {
    // 获取页面上的图纸信息部分的HTML
    const drawingInfoElement = this.$el.querySelector('.drawing-info-section');
    if (drawingInfoElement) {
      // 克隆元素以避免修改原始DOM
      const clonedElement = drawingInfoElement.cloneNode(true) as HTMLElement;

      // 移除输入框，只保留标签和值
      const inputs = clonedElement.querySelectorAll('input');
      inputs.forEach(input => {
        const valueSpan = document.createElement('span');
        valueSpan.textContent = input.value || input.placeholder || '';
        valueSpan.style.fontSize = '7px';
        input.parentNode?.replaceChild(valueSpan, input);
      });

      // 获取HTML内容
      const htmlContent = clonedElement.outerHTML;

      // 返回包含样式的完整HTML
      return `
        <tr>
          <td colspan="4" style="padding: 0;">
            ${htmlContent}
          </td>
        </tr>
      `;
    }
    return '';
  }
}
</script>

<style lang="scss" scoped>
.line-chart-container {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #f5f5f5;
  overflow: hidden;
  // min-height: 800px;
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 16px;
  background: white;
  border-bottom: 1px solid #e8e8e8;

  h3 {
    margin: 0;
    color: #333;
    font-size: 18px;
  }

  .zoom-controls {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
  }

  .control-group {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: #f8f9fa;
    border-radius: 6px;
    border: 1px solid #e9ecef;
  }

  .control-label {
    font-size: 12px;
    font-weight: 500;
    color: #495057;
    white-space: nowrap;
  }

  .time-picker {
    width: 280px !important;
  }

  .zoom-percent {
    font-size: 12px;
    color: #6c757d;
    font-weight: 500;
  }

  .zoom-mode-buttons {
    display: flex;
    gap: 4px;
  }

  .mode-btn {
    padding: 6px 12px;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    background: white;
    color: #495057;
    font-size: 12px;
    cursor: pointer;
    transition: all 0.2s ease;

    &:hover {
      border-color: #0d6efd;
      background: #f8f9fa;
    }

    &.active {
      background: #0d6efd;
      color: white;
      border-color: #0d6efd;
    }
  }

  .action-buttons-group {
    gap: 6px;
  }

  .action-btn {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;

    &.reset-btn {
      background: #6c757d;
      color: white;

      &:hover {
        background: #5a6268;
      }
    }

    &.print-btn {
      background: #0dcaf0;
      color: white;

      &:hover {
        background: #31d2f2;
      }
    }

    &.export-btn {
      background: #198754;
      color: white;

      &:hover {
        background: #157347;
      }
    }
  }
}

.chart-wrapper {
  flex: 1;
  overflow: visible;
  cursor: grab;
  background: white;
  padding: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  // min-width: 1200px;
  // min-height: 700px;

  &:active {
    cursor: grabbing;
  }
}

.grid-svg {
  width: 100%;
  height: 100%;
  display: block;
}

.axes {
  stroke: #333;
  stroke-width: 2;
}

.ruler-marks {
  text {
    font-family: Arial, sans-serif;
    font-size: 12px;
    fill: #333;
  }
}

.line-chart {
  path {
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  circle {
    cursor: pointer;
    transition: r 0.2s ease;

    // &:hover {
    //   r: 6;
    // }
  }

  .tooltip {
    position: absolute;
    background: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    pointer-events: none;
    z-index: 1000;
    transform: translate(-50%, -100%);
  }

  .drawing-info-table {
    position: absolute;
    bottom: 20px;
    right: 20px;
    display: block;
    font-size: 10px;
    border: 1px solid #333;
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

    table {
      border-collapse: collapse;
      width: 200px;
      background: white;

      td {
        border: 1px solid #333;
        padding: 2px 4px;
        text-align: center;

        &.label {
          background: #f0f0f0;
          font-weight: bold;
          width: 30%;
        }

        &.value {
          background: white;
          width: 20%;
        }
      }
    }
  }

  /* 打印样式 */
  @media print {
    .line-chart-container {
      width: 100% !important;
      height: auto !important;
      background: white !important;
    }

    .chart-header {
      display: none !important;
    }

    .chart-wrapper {
      margin: 0 !important;
      box-shadow: none !important;
      border-radius: 0 !important;
      overflow: visible !important;
    }

    .grid-svg {
      width: 100% !important;
      height: auto !important;
    }

    /* 确保打印时颜色正确显示 */
    * {
      -webkit-print-color-adjust: exact !important;
      print-color-adjust: exact !important;
    }

    .drawing-info-header {
      display: none !important;
    }

    .drawing-info-table {
      display: block !important;
      position: absolute !important;
      bottom: 20px !important;
      right: 20px !important;
      font-size: 8px !important;
      z-index: 1000 !important;
      background: white !important;
      box-shadow: none !important;

      table {
        width: 180px !important;
        border: 1px solid #000 !important;

        td {
          border: 1px solid #000 !important;
          padding: 1px 2px !important;
          font-size: 8px !important;

          &.label {
            background: #f0f0f0 !important;
            font-weight: bold !important;
          }

          &.value {
            background: white !important;
          }
        }
      }
    }
  }
}
.horizontal-top-right-legend {
  .legend-background {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.12));
  }

  .legend-item {
    cursor: default;
  }

  .legend-line {
    stroke-linecap: round;
  }

  .legend-text {
    font-family: Arial, sans-serif;
    font-size: 11px;
    fill: #333333;
    // dominant-baseline: middle;
    font-weight: 500;
  }
}

.drawing-info-section {
  margin: 10px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.drawing-info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 10px;
  padding: 10px;
}

.info-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.field-label {
  font-size: 12px;
  color: #6c757d;
  font-weight: 500;
}

.field-input {
  padding: 5px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  font-size: 12px;
  transition: border-color 0.2s ease;

  &:focus {
    outline: none;
    border-color: #0d6efd;
    box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25);
  }

  &:disabled {
    background: #e9ecef;
    color: #6c757d;
    cursor: not-allowed;
  }
}
</style>
